嗨,我是Hogan
目前在經營自己的自媒體 hogan.tech
主要分享一些有關於程式碼、軟體和科技業經驗分享
有興趣的讀者可以進一步關注我,進而獲得更多資訊唷!
未來文章一併更新於此網站 Hogan.B Lab
並且包含多語系 繁體中文、英文、日文、簡體中文
觀看分類:React 白話文運動、其他系列
如果想要快速查找其他文章請點選目錄
成立 hogan.tech 的初衷是
希望每個正在這條路上探索的人,
都可以透過 Hogan.tech 嘗試進入程式領域。
前一篇會介紹另一種狀態管理- Zustand
這一篇會繼續講解 Zustand
下面兩個簡單的用法,是針對JavaScript的使用者。
Zustand是基於Hook建立的,因此第一個建立的就是由Custom Hook建立的Store裡面可以放入包含變數、物件、函數。並且可以透過Set、Get來去做資料的「狀態管理」
import create from 'zustand'
const useBearStore = create((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}))
因為是使用Hook,因此在任何元件中皆可以直接載入做使用。也可以針對這些狀態進行渲染,可以看到短短的幾行就可以處理完成,算是Zustand中的一大福音。
function BearCounter() {
const bears = useBearStore((state) => state.bears)
return <h1>{bears} around here ...</h1>
}
function Controls() {
const increasePopulation = useBearStore((state) => state.increasePopulation)
return <button onClick={increasePopulation}>one up</button>
}
這邊也針對TypeScript使用者提供簡單的Zustand範例
在Zustand 我們會使用create來去建立新的store。透過函數傳入,透過Hook來回傳狀態,並且進行再次渲染。
import create from "zustand"
type Product = { sku: string; name: string; image: string }
type CartState = {
products: Product[]
cart: { [sku: string]: number }
addToCart: (sku: string) => void
removeFromCart: (sku: string) => void
}
// Selectors
// ...
// Initialize our store with initial values and actions to mutate the state
export const useCart = create<CartState>(set => ({
products: [
// ...
],
cart: {},
// Actions
// ...
}))
這邊也另外展示Redux以及Mobx的寫法,讀者也可以比較其差異,不過這篇不會針對Redux或是Mobx進行講解,只會針對Zustand以及其狀態管理進行講解
import { createSlice, configureStore, PayloadAction } from "@reduxjs/toolkit"
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
// Slices
// Definee the shape of the state and how to mutate it
type ICart = { [sku: string]: number }
const cartInitialState: ICart = {}
const cartSlice = createSlice({
name: "cart",
initialState: cartInitialState,
reducers: {
// ...
},
})
type IProduct = { sku: string; name: string; image: string }
const productsInitialState: IProduct[] = [
// ...
]
const productsSlice = createSlice({
name: "products",
initialState: productsInitialState,
reducers: {},
})
// Actions
// ...
// Selectors
// ...
// Store
export const store = configureStore({
reducer: {
cart: cartSlice.reducer,
products: productsSlice.reducer,
},
})
// ...
const App = () => {
return (
<Provider store={store}>
<NavigationContainer>
<Stack.Navigator>{/* ... */}</Stack.Navigator>
<StatusBar style="auto" />
</NavigationContainer>
</Provider>
)
}
import { types, Instance } from "mobx-state-tree"
const Product = types.model({
sku: types.string,
name: types.string,
image: types.string,
})
// Model and type our data with mobx state tree
const CartStore = types
.model("CartStore", {
products: types.array(Product),
cart: types.map(types.number),
})
// Actions to mutate the state
.actions(store => ({
// ...
}))
// Views are like selectors
.views(self => ({
// ...
}))
type CartStoreType = Instance<typeof CartStore>
// Spin up a hook to use our store and provide initial values to it
let _cartStore: CartStoreType
export const useCart = () => {
if (!_cartStore) {
_cartStore = CartStore.create({
products: [
// ...
],
cart: {},
})
}
return _cartStore
}
https://github.com/pmndrs/zustand#why-zustand-over-redux
根據Zustand官方,列舉以上幾點,這邊也簡單講解一下
Redux本身是一個較為複雜的狀態管理工具,會有Actioins、View、State的流程
以下是Redux的官方資料流示意圖,也可以知道如果要從無到有使用Redux的狀態管理工具學習門檻是比較高的。
https://dev.to/oahehc/redux-data-flow-and-react-component-life-cycle-11n
Context 本身雖然是歸類在狀態管理,但實際上比較像是一個集中式觸發狀態的方式。
比起Zustand而言是會發散在各個檔案,不好進行管理。
https://dev-yakuza.posstree.com/en/react/context-api/
透過Zustand,將複雜的商業邏輯中的,資料以及邏輯拆開,並且針對這些東西去做模組化。除了增加可讀性之外,也讓測試更容易去撰寫。
Zustand本身是一個滿容易學習的狀態管理工具,且自己在工作產品使用上也是相對方便的,包含針對狀態進行Set、Get或是在元件中進行使用都是相對方便,滿推薦給想針對React進行狀態管理的讀者。
如果有任何建議與疑問也歡迎留言!
如果喜歡此系列文章,請不吝於按下喜歡及分享,讓更多人看到唷~